﻿//-----------------------------------------------------------------------
// <copyright file="WallViewModel.cs" company="Microsoft">
//     Copyright (c) AGALTIER, Microsoft. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace ArchiSimple.Windows.ViewModel.PlanObjects
{
    using System;
    using System.Linq;
    using ArchiSimple.Windows.Model;
    using ArchiSimple.Windows.Tools;
#if NETFX_CORE
    using global::Windows.UI.Xaml.Controls;
    using global::Windows.UI.Xaml.Media;
#else
using System.Windows.Media;
#endif

    /// <summary>
    /// TODO: Provide summary section in the documentation header.
    /// </summary>
    public class WallViewModel : PlanObjectViewModel<Wall>
    {
        public WallViewModel(PlanViewModel plan, Wall model, Designer designer)
            : base(plan, model, designer)
        {
            this.begin = this.Plan.CreateOrGet(this.Current.Begin) as PointViewModel;
            Notify(begin);
            this.end = this.Plan.CreateOrGet(this.Current.End) as PointViewModel;
            Notify(end);

            AddAssociation(this.begin, this.end);

            RefreshGeometry();
        }

        private PointViewModel begin;

        public PointViewModel Begin
        {
            get
            {
                if (begin == null)
                {
                    begin = this.Plan.CreateOrGet(this.Current.Begin) as PointViewModel;
                    Notify(begin);

                    AddAssociation(this.begin, this.end);
                }

                return begin;
            }
            set
            {
                if (begin != value)
                {
                    RemoveAssociation(this.begin, this.end);
                    UnNotify(begin);
                    begin = value;
                    if (begin != null)
                    {
                        this.Current.Begin = begin.Current;
                        Notify(begin);
                        AddAssociation(this.begin, this.end);
                    }

                    RaisePropertyChanged(() => Begin);
                    RefreshGeometry();
                }
            }
        }

        private void AddAssociation(PointViewModel p1, PointViewModel p2)
        {
            if (p1 != null && p2 != null)
            {
                p1.NextPoints.Add(p2);
                p2.NextPoints.Add(p1);
            }
        }

        private PointViewModel end;

        public PointViewModel End
        {
            get
            {
                if (end == null)
                {
                    end = this.Plan.CreateOrGet(this.Current.End) as PointViewModel;
                    Notify(end);

                    AddAssociation(this.begin, this.end);
                }

                return end;
            }
            set
            {
                if (end != value)
                {
                    RemoveAssociation(this.begin, this.end);
                    UnNotify(end);
                    end = value;
                    if (end != null)
                    {
                        this.Current.End = end.Current;
                        Notify(end);
                        AddAssociation(this.begin, this.end);
                    }

                    RaisePropertyChanged(() => End);
                    RefreshGeometry();
                }
            }
        }

        private void RefreshGeometry()
        {
            double minX = double.MaxValue;
            double minY = double.MaxValue;
            double maxX = double.MinValue;
            double maxY = double.MinValue;

            if (this.begin != null)
            {
                this.Designer.SetPoint(this.wallGeometry, 0, this.begin.Current);
                minX = Math.Min(minX, this.begin.X);
                maxX = Math.Max(maxX, this.begin.X);
                minY = Math.Min(minY, this.begin.Y);
                maxY = Math.Max(maxY, this.begin.Y);
            }
            
            if (this.end != null)
            {
                this.Designer.SetPoint(this.wallGeometry, 1, this.end.Current);
                minX = Math.Min(minX, this.end.X);
                maxX = Math.Max(maxX, this.end.X);
                minY = Math.Min(minY, this.end.Y);
                maxY = Math.Max(maxY, this.end.Y);
            }

            if (this.begin == null && this.end == null)
            {
                minX = 0;
                maxX = 0;
                minY = 0;
                maxY = 0;
            }

            this.Zone = new Rectangle
            {
                X = minX,
                Y = minY,
                Width = maxX - minX,
                Height = maxY - minY,
            };
        }

        private void RemoveAssociation(PointViewModel p1, PointViewModel p2)
        {
            if (p1 != null && p2 != null)
            {
                p1.NextPoints.Remove(p2);
                p2.NextPoints.Remove(p1);
            }
        }

        private void UnNotify(PointViewModel point)
        {
        }

        private void Notify(PointViewModel point)
        {
            if (point != null)
            {
                point.Notify(p => p.X, RefreshGeometry);
                point.Notify(p => p.Y, RefreshGeometry);
            }
        }

        private PathFigure wallGeometry = null;

        public PathFigure WallGeometry
        {
            get
            {
                if (this.Begin != null && this.End != null && this.wallGeometry == null)
                {
                    this.wallGeometry = this.Designer.MakePath(new[] { this.Begin.Current, this.End.Current });
                    RaisePropertyChanged(() => SelectedGeometry);
                }

                return this.wallGeometry;
            }
        }

        public override PathGeometry SelectedGeometry
        {
            get
            {
                var geo = this.WallGeometry;

                if (geo == null)
                {
                    return null;
                }

                return new PathGeometry { Figures = new PathFigureCollection(){ geo } };
            }
        }

        public override void Delete()
        {
            var begin = this.Begin;
            var end = this.End;

            var qRoom = from r in this.Plan.PlanObjects.OfType<RoomViewModel>()
                        where r.Points.Contains(begin)
                        && r.Points.Contains(end)
                        select r;

            var rooms = qRoom.ToList();

            if (rooms.Count == 1)
            {
                rooms.First().Delete();
            }
            else if (rooms.Count == 2)
            {
            }

            this.Begin = null;
            this.End = null;

            begin.Delete();
            end.Delete();

            this.Plan.RemoveFromPlan(this);
        }

        public int Size
        {
            get
            {
                var x = this.end.X - this.begin.X;
                var y = this.end.Y - this.begin.Y;

                return (int)Math.Sqrt(x * x + y * y);
            }
            set
            {
                if (value > 1)
                {
                    var x = this.end.X - this.begin.X;
                    var y = this.end.Y - this.begin.Y;

                    var actualSize = this.Size;
                    if (this.SizeMode == WallViewModel.ExtendMode.Begin)
                    {
                        this.End.X = this.Begin.X + 1.0 * x * value / actualSize;
                        this.End.Y = this.Begin.Y + 1.0 * y * value / actualSize;
                    }
                    else
                    {
                        this.Begin.X = this.End.X - 1.0 * x * value / actualSize;
                        this.Begin.Y = this.End.Y - 1.0 * y * value / actualSize;
                    }
                }
            }
        }

        public enum ExtendMode
        {
            Begin,
            End,
        }

        public ExtendMode SizeMode
        {
            get { return this.Get<ExtendMode>("ExtendMode"); }
            set { this.Set<ExtendMode>("ExtendMode", value); }
        }
    }
}
